package com.tencent.txcc.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.tencent.txcc.domain.KillActivity;
import com.tencent.txcc.domain.KillCourse;
import com.tencent.txcc.enums.GlobleExceptionCode;
import com.tencent.txcc.exception.BusinessException;
import com.tencent.txcc.mapper.KillActivityMapper;
import com.tencent.txcc.service.IKillActivityService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.tencent.txcc.service.IKillCourseService;
import com.tencent.txcc.util.AssertUtil;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author director
 * @since 2022-10-20
 */
@Service
public class KillActivityServiceImpl extends ServiceImpl<KillActivityMapper, KillActivity> implements IKillActivityService {

    @Autowired
    private IKillCourseService killCourseService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    /**
     * 发布秒杀活动
     * @param activityId
     */
    @Override
    @Transactional
    public void publish(Long activityId) {
        // 1.判断不能为空
        KillActivity killActivity = selectById(activityId);
        AssertUtil.isNotNull(killActivity, GlobleExceptionCode.ERROR);
        // 2.判断状态
        boolean boo = KillActivity.WAIT_PUBLISH == killActivity.getPublishStatus();
        AssertUtil.isTrue(boo, GlobleExceptionCode.ERROR);

        // 3.活动开始时间在当前时间之前  发布活动的时间必须小于活动开始时间
        Date now = new Date();
        boolean isOk = killActivity.getStartTime().after(now);
        AssertUtil.isTrue(isOk, GlobleExceptionCode.ERROR);

        // 4.判断秒杀中是否有课程
        List<KillCourse> killCourses = selectKillCourseByActivityId(activityId);
        if (killCourses == null || killCourses.size() < 0){
            throw new BusinessException(GlobleExceptionCode.ERROR);
        }


        killCourses.forEach(killCourse -> {
            // 1.设置信号量
            RSemaphore semaphore = redissonClient.getSemaphore(activityId + ":" + killCourse.getId());
            boolean isSetPermits = semaphore.trySetPermits(killCourse.getKillCount());
            if (isSetPermits){
                // 2.放入到Redis中 // hash结构中有个方法：keys("activity:")
                // 此处必须要求两个Key为string，否则报错
                redisTemplate.opsForHash().put(
                        "activity:" + activityId,
                        killCourse.getId().toString(),
                        killCourse
                );
                // 3.修改状态，时间
                killCourse.setPublishStatus(KillActivity.ON_PUBLISH);
                killCourse.setPublishTime(now);
                killCourseService.updateById(killCourse);
            }
        });


        // 修改秒杀活动状态，发布时间
        killActivity.setPublishStatus(KillActivity.ON_PUBLISH);
        killActivity.setPublishTime(now);
        updateById(killActivity);

    }

    private List<KillCourse> selectKillCourseByActivityId(Long activityId) {
        Wrapper<KillCourse> wrapper = new EntityWrapper<>();
        wrapper.eq("activity_id", activityId);
        return killCourseService.selectList(wrapper);
    }
}
